package com.yenole.flutterblockchain;

import android.app.Activity;
import android.content.Context;

import com.yenole.blockchain.wallet.BTCUtil;
import com.yenole.blockchain.wallet.DCRUtil;
import com.yenole.blockchain.wallet.EOSUtil;
import com.yenole.blockchain.wallet.ETHUtil;
import com.yenole.blockchain.wallet.model.BIP44Util;
import com.yenole.blockchain.wallet.transaction.btc.BitcoinTransaction;
import com.yenole.blockchain.wallet.transaction.dcr.DecredTransaction;
import com.yenole.blockchain.wallet.transaction.eos.EOSTransaction;
import com.yenole.blockchain.wallet.transaction.eth.EthereumTransaction;

import java.util.ArrayList;
import java.math.BigInteger;
import java.io.File;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/**
 * FlutterBlockchainPlugin
 */
public class FlutterBlockchainPlugin implements MethodCallHandler {
    private static String dcrdir;
    private static Activity context;

    /**
     * Plugin registration.
     */
    public static void registerWith(Registrar registrar) {
        dcrdir = registrar.activeContext().getFilesDir() + "/wallet";
        context = registrar.activity();
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_blockchain");
        channel.setMethodCallHandler(new FlutterBlockchainPlugin());
    }

    @Override
    public void onMethodCall(MethodCall call, final Result result) {
        if (call.method.equals("getPlatformVersion")) {
            result.success("Android " + android.os.Build.VERSION.RELEASE);
        } else if (call.method.equals("eos.randomPrivate")) {
            result.success(EOSUtil.randomPrivate());
        } else if (call.method.equals("eos.privateToPublic")) {
            String key = call.argument("private");
            result.success(EOSUtil.private2Public(key));
        } else if (call.method.equals("eos.pushTransaction")) {
            String contract = call.argument("contract");
            String action = call.argument("action");
            String args = call.argument("args");
            String binargs = call.argument("binargs");
            String permission = call.argument("permission");
            String privateKey = call.argument("private");
            String blockId = call.argument("blockid");
            String expiration = call.argument("expiration");
            String chainId = call.argument("chainid");
            try {
                EOSTransaction transaction = new EOSTransaction();
                transaction.action(contract, action, args, permission, binargs);
                result.success(transaction.execute(privateKey, blockId, expiration, chainId));
            } catch (Exception e) {
                e.printStackTrace();
                result.success("");
            }
        } else if (call.method.equals("btc.Test3Net")) {
            boolean isTest = call.argument("istest");
            BTCUtil.Test3Net(isTest);
            result.success(true);
        } else if (call.method.equals("btc.randomMnemonic")) {
            result.success(BTCUtil.randomMnemonic());
        } else if (call.method.equals("btc.segAddress")) {
            String mnemonic = call.argument("mnemonic");
            String path = BTCUtil.IsTest3Net() ? BIP44Util.BITCOIN_SEGWIT_TESTNET_PATH : BIP44Util.BITCOIN_SEGWIT_MAIN_PATH;
            result.success(BTCUtil.segAddress(mnemonic, path));
        } else if (call.method.equals("btc.transfer")) {
            String mnemonic = call.argument("mnemonic");
            String toAddress = call.argument("address");
            int amount = call.argument("amount");
            int fee = call.argument("fee");
            ArrayList<String> utxos = call.argument("utxos");
            String path = BTCUtil.IsTest3Net() ? BIP44Util.BITCOIN_SEGWIT_TESTNET_PATH : BIP44Util.BITCOIN_SEGWIT_MAIN_PATH;
            String fromAddress = BTCUtil.segAddress(mnemonic, path);
            String xprv = BTCUtil.xprv(mnemonic, path);
            String scriptPubKey = BTCUtil.scriptPubkey(mnemonic, path);
            try {
                BitcoinTransaction transaction = new BitcoinTransaction();
                transaction.sendto(fromAddress, scriptPubKey, toAddress, amount, fee);
                result.success(transaction.execute(xprv, utxos));
            } catch (Exception ex) {
                ex.printStackTrace();
                result.success("");
            }
        } else if (call.method.equals("eth.address")) {
            String mnemonic = call.argument("mnemonic");
            result.success(ETHUtil.Address(mnemonic));
        } else if(call.method.equals("eth.tokendata")) {
            String address = call.argument("address");
            String amount = call.argument("amount").toString();
            result.success(ETHUtil.GenerateTokenData(address,Long.valueOf(amount)));
        } else if (call.method.equals("eth.transfer")) {
            int chainid = call.argument("chainid");
            String mnemonic = call.argument("mnemonic");
            String address = call.argument("address");
            String data = call.argument("data");
            int nonce = call.argument("nonce");
            int gasLimit = call.argument("gaslimit");
            String gasPrice = call.argument("gasprice").toString();
            double amount = call.argument("amount");
            try {
                EthereumTransaction transaction = new EthereumTransaction(BigInteger.valueOf(nonce), BigInteger.valueOf(Long.valueOf(gasPrice)), BigInteger.valueOf(gasLimit), address, BigInteger.valueOf((long)(amount*1e18)), data);
                byte[] privateKey = ETHUtil.privateKey(mnemonic);
                String rawTx = transaction.signTransaction(chainid, privateKey);
                result.success(rawTx);
            } catch (Exception ex) {
                ex.printStackTrace();
                result.success("");
            }
        } else if (call.method.equals("dcr.mnemonic")) {
            result.success(DCRUtil.randomMnemonic());
        } else if (call.method.equals("dcr.address")) {
            final String mnemonic = call.argument("mnemonic");
            final String netparam = call.argument("netparam");
            deleteFile(new File(dcrdir));
            new Thread(){
                @Override
                public void run() {
                    final String address = DCRUtil.address(dcrdir, mnemonic, netparam);
                    context.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            result.success(address);
                        }
                    });
                }
            }.start();
        } else if (call.method.equals("dcr.transaction")) {
            final String mnemonic = call.argument("mnemonic");
            final String netparam = call.argument("netparam");
            String address = call.argument("address");
            double amount = call.argument("amount");
            ArrayList<String> utxos = call.argument("utxos");
            deleteFile(new File(dcrdir));
            final DecredTransaction transaction = new DecredTransaction(dcrdir);
            transaction.setAddress(address);
            transaction.setAmount(amount);
            for (String utxo : utxos) {
                String[] strs = utxo.split(",");
                transaction.unspent(strs[0], strs[1], Integer.parseInt(strs[2]), Double.parseDouble(strs[3]));
            }
            new Thread(){
                @Override
                public void run() {
                    final String txhash = transaction.signTransaction(mnemonic,netparam);
                    context.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            result.success(txhash);
                        }
                    });
                }
            }.start();
        } else {
            result.notImplemented();
        }
    }

    private static void deleteFile(File file){
        if (file.isFile()){//判断是否为文件，是，则删除
            System.out.println(file.getAbsoluteFile());//打印路径
            file.delete();
        }else{//不为文件，则为文件夹
            try{
                String[] childFilePath = file.list();//获取文件夹下所有文件相对路径
                for (String path:childFilePath){
                    File childFile= new File(file.getAbsoluteFile()+"/"+path);
                    deleteFile(childFile);//递归，对每个都进行判断
                }
                System.out.println(file.getAbsoluteFile());
                file.delete();
            } catch (Exception exception){
                System.out.println(exception);
            }
        }
    }
}
